package com.macro.mall.tiny.util;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 敏感词工具类
 * 功能：
 * 1. 文本中是否包含敏感词
 * 2. 文本脱敏处理
 * 3. 统计文本中敏感词数量
 * 4. 新增敏感词到文本文件
 * 5. 查询文本中的敏感词（分页）
 * 6. 删除敏感词
 * @author ikun
 */
public class SensitiveWordUtil {
    //敏感词文本读取的时候 读取结束--打上标记
    private static final Character END_CHAR = '\0';
    private final Map<Character, Object> sensitiveWordTree = new HashMap<>();
    private final Set<String> sensitiveWords = new HashSet<>();

    private final String wordFilePath ;

    private static final int DEFAULT_PAGE_SIZE = 10;
    /**
     * 构造函数
     * @param wordFilePath 敏感词文件路径
     */
    public SensitiveWordUtil(String wordFilePath) {
        this.wordFilePath = wordFilePath;
        loadSensitiveWords();
    }

    /**
     * 从文件加载敏感词
     */
    private  void loadSensitiveWords() {
        sensitiveWords.clear();
        sensitiveWordTree.clear();
        try (BufferedReader reader = new BufferedReader(
                //以流的方式读取文件 utf-8防止中文乱码
                new InputStreamReader(
                        new FileInputStream(wordFilePath),
                        StandardCharsets.UTF_8))) {
            String line;
            //while sensitiveWords 将敏感词放入set集合中
            while ((line = reader.readLine()) != null) {
                if (!line.trim().isEmpty()) {
                    sensitiveWords.add(line.trim());
                }
            }
            // 初始化敏感词树
            for (String word : sensitiveWords) {
                //构建一个 map 敏感词树
                Map<Character, Object> currentNode = sensitiveWordTree;
                for (char c : word.toCharArray()) {
                    currentNode = (Map<Character, Object>) currentNode.computeIfAbsent(c, k -> new HashMap<>());
                }
                currentNode.put(END_CHAR, true);
            }
            System.out.println("成功加载敏感词: " + sensitiveWords.size() + " 个");
        } catch (IOException e) {
            System.err.println("加载敏感词文件失败: " + e.getMessage());
        }
    }

    /**
     * 重新加载敏感词
     */
    public void reload() {
        loadSensitiveWords();
    }

    /**
     * 检查文本是否包含敏感词
     * @param text 待检查文本
     * @return 是否包含敏感词
     */
    public boolean containsSensitiveWord(String text) {
        if (text == null || text.isEmpty()) {
            return false;
        }

        char[] chars = text.toCharArray();
        int i = 0;
        int n = chars.length;

        while (i < n) {
            Map<Character, Object> node = sensitiveWordTree;
            int j = i;
            boolean found = false;

            while (j < n) {
                node = (Map<Character, Object>) node.get(chars[j]);
                if (node == null){
                    break;
                }

                if (Boolean.TRUE.equals(node.get(END_CHAR))) {
                    return true;
                }
                j++;
            }
            i++;
        }
        return false;
    }

    /**
     * 过滤敏感词（脱敏处理）
     * @param text 原始文本
     * @return 脱敏后的文本
     */
    public String filter(String text) {
        return filter(text, '*');
    }

    /**
     * 过滤敏感词（脱敏处理）
     * @param text 原始文本
     * @param replacement 替换字符
     * @return 脱敏后的文本
     */
    public String filter(String text, char replacement) {
        if (text == null || text.isEmpty()) {
            return text;
        }
        char[] chars = text.toCharArray();
        StringBuilder result = new StringBuilder();
        int i = 0;
        int n = chars.length;
        while (i < n) {
            Map<Character, Object> node = sensitiveWordTree;
            int j = i;
            // 记录匹配结束位置
            int matchEnd = -1;
            // 尝试匹配以i开头的敏感词
            while (j < n) {
                node = (Map<Character, Object>) node.get(chars[j]);
                if (node == null){
                    break;
                }
                if (Boolean.TRUE.equals(node.get(END_CHAR))) {
                    // 记录可能的结束位置
                    matchEnd = j;
                }
                j++;
            }
            if (matchEnd != -1) {
                // 替换敏感词 - Java 8 兼容版本
                int replaceLength = matchEnd - i + 1;
                appendStars(result, replaceLength);
                // 跳过敏感词
                i = matchEnd + 1;
            } else {
                // 没有敏感词，添加当前字符
                result.append(chars[i]);
                i++;
            }
        }
        return result.toString();
    }
    // 创建指定长度的星号字符串
    private void appendStars(StringBuilder sb, int length) {
        for (int i = 0; i < length; i++) {
            sb.append('*');
        }
    }
    /**
     * 统计文本中敏感词数量
     * @param text 待统计文本
     * @return 敏感词数量
     */
    public int countSensitiveWords(String text) {
        if (text == null || text.isEmpty()) {
            return 0;
        }

        Set<String> foundWords = findSensitiveWords(text);
        return foundWords.size();
    }

    /**
     * 查找文本中的所有敏感词
     * @param text 待检查文本
     * @return 敏感词集合
     */
    public Set<String> findSensitiveWords(String text) {
        Set<String> foundWords = new HashSet<>();
        if (text == null || text.isEmpty()) {
            return foundWords;
        }

        char[] chars = text.toCharArray();
        int i = 0;
        int n = chars.length;

        while (i < n) {
            Map<Character, Object> node = sensitiveWordTree;
            int j = i;
            int matchStart = i;
            int matchEnd = -1;
            StringBuilder currentWord = new StringBuilder();

            while (j < n) {
                char c = chars[j];
                node = (Map<Character, Object>) node.get(c);
                if (node == null) {
                    break;
                }

                currentWord.append(c);
                if (Boolean.TRUE.equals(node.get(END_CHAR))) {
                    matchEnd = j;
                    foundWords.add(currentWord.toString());
                }
                j++;
            }

            if (matchEnd != -1) {
                i = matchEnd + 1;
            } else {
                i++;
            }
        }
        return foundWords;
    }

    /**
     * 分页查询文本中的敏感词
     * @param text 待检查文本
     * @param pageNum 页码
     * @param pageSize 每页数量
     * @return 敏感词列表
     */
    public List<String> findSensitiveWords(String text, int pageNum, int pageSize) {
        Set<String> allWords = findSensitiveWords(text);
        List<String> wordList = new ArrayList<>(allWords);

        // 分页处理
        int start = (pageNum - 1) * pageSize;
        if (start >= wordList.size()) {
            return Collections.emptyList();
        }

        int end = Math.min(start + pageSize, wordList.size());
        return wordList.subList(start, end);
    }

    /**
     * 分页查询文本中的敏感词（使用默认分页大小）
     * @param text 待检查文本
     * @param pageNum 页码
     * @return 敏感词列表
     */
    public List<String> findSensitiveWords(String text, int pageNum) {
        return findSensitiveWords(text, pageNum, DEFAULT_PAGE_SIZE);
    }

    /**
     * 添加敏感词到文件（防止重复添加，保持文件格式规范）
     * @param words 敏感词集合
     * @return 实际添加的新敏感词数量
     */
    public int addSensitiveWords(Collection<String> words) {
        if (words == null || words.isEmpty()) {
            return 0;
        }

        // 过滤掉已存在的敏感词
        Set<String> newWords = new HashSet<>();
        for (String word : words) {
            String normalizedWord = normalizeWord(word);
            if (!sensitiveWords.contains(normalizedWord) && !normalizedWord.isEmpty()) {
                newWords.add(normalizedWord);
            }
        }

        if (newWords.isEmpty()) {
            System.out.println("没有新的敏感词需要添加");
            return 0;
        }

        try {
            Path path = Paths.get(wordFilePath);

            // 确保文件以换行符结尾
            ensureFileEndsWithNewline(path);

            // 构建要追加的内容（每个词一行）
            List<String> linesToAppend = newWords.stream()
                    .map(word -> word + System.lineSeparator())
                    .collect(Collectors.toList());

            // 追加新词到文件
            Files.write(path,
                    linesToAppend,
                    StandardCharsets.UTF_8,
                    StandardOpenOption.APPEND);

            // 更新内存中的敏感词集合
            sensitiveWords.addAll(newWords);

            // 更新敏感词树
            for (String word : newWords) {
                addWordToTree(word);
            }

            System.out.println("成功添加 " + newWords.size() + " 个新敏感词");
            return newWords.size();
        } catch (IOException e) {
            System.err.println("添加敏感词失败: " + e.getMessage());
            return -1;
        }
    }

    /**
     * 添加单个敏感词到文件（防止重复添加，保持文件格式规范）
     * @param word 敏感词
     * @return 添加结果: true=添加成功, false=词已存在或添加失败
     */
    public boolean addSensitiveWord(String word) {
        if (word == null || word.isEmpty()) {
            return false;
        }

        String normalizedWord = normalizeWord(word);

        if (sensitiveWords.contains(normalizedWord)) {
            System.out.println("敏感词已存在: " + normalizedWord);
            return false;
        }

        try {
            Path path = Paths.get(wordFilePath);

            // 确保文件以换行符结尾
            ensureFileEndsWithNewline(path);

            // 追加新词到文件（带换行符）
            Files.write(path,
                    Collections.singletonList(normalizedWord + System.lineSeparator()),
                    StandardCharsets.UTF_8,
                    StandardOpenOption.APPEND);

            // 更新内存中的敏感词集合
            sensitiveWords.add(normalizedWord);

            // 更新敏感词树
            addWordToTree(normalizedWord);

            System.out.println("成功添加敏感词: " + normalizedWord);
            return true;
        } catch (IOException e) {
            System.err.println("添加敏感词失败: " + e.getMessage());
            return false;
        }
    }

    /**
     * 确保文件以换行符结尾
     */
    private void ensureFileEndsWithNewline(Path path) throws IOException {
        if (Files.exists(path)){
            // 读取文件最后一行
            List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
            if (!lines.isEmpty()) {
                String lastLine = lines.get(lines.size() - 1);

                // 检查最后一行是否以换行符结尾
                if (!lastLine.isEmpty()) {
                    // 追加一个换行符
                    Files.write(path,
                            Collections.singletonList(System.lineSeparator()),
                            StandardCharsets.UTF_8,
                            StandardOpenOption.APPEND);
                }
            }
        }
    }

    /**
     * 添加单词到敏感词树
     */
    private void addWordToTree(String word) {
        Map<Character, Object> currentNode = sensitiveWordTree;
        for (char c : word.toCharArray()) {
            currentNode = (Map<Character, Object>) currentNode.computeIfAbsent(c, k -> new HashMap<>());
        }
        currentNode.put(END_CHAR, true);
    }

    /**
     * 规范化敏感词
     * - 去除首尾空格
     * - 转换为小写（可选）
     * - 其他规范化处理
     */
    private String normalizeWord(String word) {
        // 去除首尾空格
        String normalized = word.trim();

        // 转换为小写（根据需求决定）
        // normalized = normalized.toLowerCase();

        // 其他规范化处理（如全角转半角等）

        return normalized;
    }

    /**
     * 从文件中删除敏感词
     * @param words 要删除的敏感词集合
     */
    public int removeSensitiveWords(Collection<String> words) {
        try {
            // 读取所有敏感词
            List<String> allWords = Files.readAllLines(Paths.get(wordFilePath), StandardCharsets.UTF_8);

            // 移除指定敏感词
            allWords.removeAll(words);

            // 重新写入文件
            Files.write(Paths.get(wordFilePath), allWords, StandardCharsets.UTF_8);

            // 重新加载敏感词
            reload();
            return allWords.size();
        } catch (IOException e) {
            System.err.println("删除敏感词失败: " + e.getMessage());
        }
        return 0;
    }

    /**
     * 删除单个敏感词
     * @param word 要删除的敏感词
     */
    public void removeSensitiveWord(String word) {
        removeSensitiveWords(Collections.singletonList(word));
    }

    /**
     * 获取所有敏感词
     * @return 敏感词集合
     */
    public Set<String> getAllSensitiveWords() {
        return new HashSet<>(sensitiveWords);
    }

    /**
     * 创建替换字符串
     * @param sb 字符串构建器
     * @param length 替换长度
     * @param replacement 替换字符
     */
    private void appendReplacement(StringBuilder sb, int length, char replacement) {
        for (int i = 0; i < length; i++) {
            sb.append(replacement);
        }
    }
}